#include "SSCompanyReportManager.h"
#include "CompanyReport.h"
#include <core/time/time.h>
#include <core/system/system_util.h>
#if WIN32
#include <windows.h>
#endif

using namespace qb::base;
class StatDumper{
	typedef qb::base::HighResTime HighResTime;
	typedef CReportManagerBase::kActionType kActionType;
	enum {
		kActionTypeCount = CReportManagerBase::kActionTypeCount
	};
	struct StatInfo{
		kActionType	type;		// 当前操作的类型
		double		time;		// 当前操作的起始时间
		double		last;		// 当前操作的持续时间
		double		gap;		// 与上次的间隔时间
	};
	typedef qb::base::BaseString BaseString;
	typedef list<StatInfo> StatInfoList;
protected://不变量
	int				m_item_size;	// T的大小
	int				m_max_count;	// m_datas允许的最大个数
	uint32_t			m_log_gap;		// 写日志的间隔时间
protected:
	int				m_total;		// 总共个数,包括删除
	int				m_length;
	uint32_t			m_log_last;		// 最近入队时间
	int				m_log_total;	// 写日志时的total
	StatInfoList	m_datas;		// 最近加入的统计信息队列
	double			m_speed;		// 调用速度,多少次每秒,m_datas中首尾时间差/个数
	HighResTime		m_total_last;	// m_datas中的last之和
	HighResTime		m_total_gap;	// m_datas中的gap之和
	HighResTime		m_total_action;
	string			m_name;
	int				m_action[kActionTypeCount];
	CReportManagerBase*	m_reportmanager;
public:
	StatDumper(CReportManagerBase* rm) :m_reportmanager(rm),
		m_item_size(0), m_total(0), m_max_count(1024),
		m_log_last(GetTickCount()), m_log_gap(4000), m_length(0), m_speed(0.0), m_log_total(0),
		m_total_last(0.0), m_total_gap(0.0), m_total_action(0.0)
	{
		for (int i = 0; i < kActionTypeCount; i++)m_action[i] = 0.0;
	}
	~StatDumper(){}
	void SetItemSize(int itemSize){ m_item_size = itemSize; }
	void SetName(const char* name){ m_name = name ? name : ""; }
	void Add(double time, kActionType type, int length)
	{
		m_total++;
		int ndelete = m_datas.size() - m_max_count;
		for (StatInfoList::iterator it = m_datas.begin(); ndelete > 0 && it != m_datas.end();)
		{
			StatInfo& si = *it;
			m_total_gap -= si.gap;
			m_total_last -= si.last;
			it = m_datas.erase(it);
			ndelete--;
		}
		m_length = length;
		m_total_last += time;
		m_total_action += time;
		m_action[type] += 1;

		HighResTime cur;
		StatInfo si;
		si.last = time;
		si.time = cur - HighResTime(time);
		si.type = type;
		si.gap = 0.0;
		if (m_datas.size() > 0)
		{
			StatInfoList::reverse_iterator rit = m_datas.rbegin();
			StatInfo end = *rit;
			si.gap = si.time - (end.time + end.last);
			m_total_gap += si.gap;

			StatInfoList::iterator it = m_datas.begin();
			StatInfo& start = *it;
			m_speed = (si.time + si.last - start.time) * 1000000 / (m_datas.size() + 1);
		}
		else
			m_speed = si.last * 1000000 / 1.0;
		m_datas.push_back(si);
		uint32_t tick = GetTickCount();
		if (m_log_last + m_log_gap <= tick)
		{
			Dump();
			m_log_last = tick;
		}
	}
	const char* GetActionName(kActionType type)
	{
		const char* names[] = { "Add", "Clear", "ClearReport", "Reserve", "GetReport", "GetReportOrAdd", "SetReport", "None" };
		int index = type;
		index = (index < 0 || index >= kActionTypeCount) ? kActionTypeCount : index;
		return names[index];
	}
	void Dump()
	{
		int nincrease = m_total - m_log_total;
		int ncount = m_datas.size();
		if (ncount <= 0 || m_total <= 0)
			return;
		uint32_t tick = GetTickCount();
		if (tick == m_log_last)
			return;

		int mem = m_reportmanager->GetMemory(0);
		int mem_real = m_reportmanager->GetMemory(1);
		float mem_ratio = mem == 0 ? 0 : (mem_real*100.0 / mem);
		int nsize = m_reportmanager->GetSize();
		float speed = nincrease * 1000 / (tick - m_log_last);
		BaseString str = qb::base::os::fmtstr("[MEMORY][REPORT]0x%8x-%24s,len:%6d,total:%8d,speed:%.2f/s,item:%4d mem:%8d/%8d/%2.2f%% size:%8d,last_avg:%8dus gap_avg:%8dus  ",
			this,m_name.c_str(),
			m_length, m_total, speed, m_item_size, mem_real, mem, mem_ratio, nsize, m_total_last.microsec() / ncount, m_total_gap.microsec() / ncount
			);
		for (int i = 0; i < kActionTypeCount; i++)
		{
			str += qb::base::os::fmtstr("%s-%dms-%.2f, ",
				GetActionName((kActionType)i), m_action[i], m_action[i] * 100.0 / m_total
				);
		}
		//qb::base::DebugView(0, 0, 0, "%s", str.c_str());
		m_log_total = m_total;
	}
};

CReportManagerBase::CReportManagerBase() :m_dumper(new StatDumper(this))
{

}
CReportManagerBase::~CReportManagerBase()
{
	if (m_dumper)
		delete m_dumper;
	m_dumper = nullptr;
}
int CReportManagerBase::GetSize() const
{
	return 0;
}
int CReportManagerBase::GetMemory(int mode)
{
	return 0;
}
void CReportManagerBase::SetName(const char* name)
{
	if (m_dumper)
		m_dumper->SetName(name);
}
void CReportManagerBase::SetItemSize(int itemSize)
{
	if (m_dumper)
		m_dumper->SetItemSize(itemSize);
}
void CReportManagerBase::DumpStatus(int mode /*= 0*/) const
{
	ScopedLockType lock(const_cast<LockType&>(m_mutex));
	const_cast<StatDumper*>(m_dumper)->Dump();
}

CReportManagerBase::ScopedDumper::ScopedDumper(StatDumper* dumper, kActionType type, int length) :m_dumper(dumper),
m_type(type), m_length(length){}
CReportManagerBase::ScopedDumper::~ScopedDumper(){ m_dumper->Add(m_timer.elapsed(), m_type, m_length); }


CSSReportManager<CBondCompanyRep> * GetBrokerReportManager()
{
	static CSSReportManager<CBondCompanyRep> mng;
	return &mng;
}



CSSReportManager<CBondBankRep> * GetBankClientReportManager()
{
	static CSSReportManager<CBondBankRep> mng;
	return &mng;
}

CSSReportManager<CBondBankRep> * GetBankReportManager()
{
	static CSSReportManager<CBondBankRep> mng;
	return &mng;
}

CSSReportManager<CXCQuoteRep> * GetXCQuoteReportManager()
{
	static CSSReportManager<CXCQuoteRep> mng;
	return &mng;
}

CSSCFETSReportManager<CCFETSQuoteRep> * GetCfetsReportManager()
{
	static CSSCFETSReportManager<CCFETSQuoteRep> mng;
	return &mng;
}


CSSCFETSDealQuoteManager<CCFETSDealQuoteRep> *	GetCfetsDealQuoteManager()
{
	static CSSCFETSDealQuoteManager<CCFETSDealQuoteRep> mng;
	return &mng;
}